/**
 * ProtoActor TypeScript SDK 事件监听示例
 * 
 * 此示例展示了如何订阅和处理 Actor 系统中的事件
 * 运行方式: bun run example:events
 */

import { Actor } from '../actor/actor';
import { Context } from '../actor/context';
import { Props } from '../actor/props';
import { PID } from '../actor/pid';
import { RootContext } from '../actor/rootContext';
import { ActorSystem } from '../actor/actorSystem';
import { Events } from '../actor/eventStream';
import { SupervisorDirective } from '../actor/supervisorDirective';

// 定义一个包含监督策略的Actor
class SupervisedActor implements Actor {
  constructor(private name: string) {}

  // 可选的预重启处理方法
  preRestart(): void {
    console.log(`[${this.name}] 正在准备重启...`);
  }

  // 可选的重启后处理方法
  postRestart(): void {
    console.log(`[${this.name}] 已完成重启`);
  }

  // 可选的停止处理方法
  postStop(): void {
    console.log(`[${this.name}] 已停止`);
  }

  async receive(context: Context): Promise<void> {
    const message = context.message();
    
    if (typeof message === 'string') {
      console.log(`[${this.name}] 收到消息: ${message}`);
      
      // 如果收到"停止"消息，则停止自己
      if (message === 'stop') {
        console.log(`[${this.name}] 收到停止命令，即将停止...`);
        context.stop(context.self());
      }
      // 如果收到"崩溃"消息，则抛出异常
      else if (message === 'crash') {
        console.log(`[${this.name}] 收到崩溃命令，即将抛出异常...`);
        throw new Error('Actor崩溃测试');
      }
    } else {
      console.log(`[${this.name}] 收到未知类型消息:`, message);
    }
  }
}

// 运行示例
async function runExample() {
  console.log('===== ProtoActor TypeScript 事件监听示例 =====\n');

  // 创建 Actor System
  const system = new ActorSystem();
  
  // 订阅 Actor 生命周期事件
  console.log('正在订阅 Actor 生命周期事件...');
  
  // 订阅 Actor 启动事件
  system.eventStream.subscribe(Events.ActorStarted, (event: Events.ActorStarted) => {
    console.log(`[事件] Actor 已启动: ${event.pid.toString()}`);
  });
  
  // 订阅 Actor 停止事件
  system.eventStream.subscribe(Events.ActorStopped, (event: Events.ActorStopped) => {
    console.log(`[事件] Actor 已停止: ${event.pid.toString()}`);
  });
  
  // 订阅 Actor 重启事件
  system.eventStream.subscribe(Events.ActorRestarted, (event: Events.ActorRestarted) => {
    console.log(`[事件] Actor 已重启: ${event.pid.toString()}, 原因: ${event.reason.message}`);
  });
  
  // 订阅系统错误事件
  system.eventStream.subscribe(Events.SystemError, (event: Events.SystemError) => {
    console.log(`[事件] 系统错误: ${event.message}, 错误详情: ${event.error.message}`);
  });
  
  // 订阅无效信件事件
  system.eventStream.subscribe(Events.DeadLetter, (event: Events.DeadLetter) => {
    console.log(`[事件] 无效信件: 发送到 ${event.pid.toString()}, 消息类型: ${typeof event.message}`);
  });
  
  // 创建 Root Context
  const context = new RootContext(system);

  try {
    // 定义带有重启策略的Props
    const props = Props.fromProducer(() => new SupervisedActor('TestActor'))
                       .withSupervisor({
                         handleFailure: (pid, error) => {
                           console.log(`[监督者] 处理Actor故障: ${pid.toString()}, 错误: ${error.message}`);
                           return SupervisorDirective.Restart; // 总是重启Actor
                         }
                       });

    // 创建 Actor
    console.log('\n--- 创建 Actor ---');
    const pid = await context.spawnNamed(props, 'testactor');
    console.log(`创建了 Actor: ${pid.toString()}`);

    // 等待一会儿以便看到启动事件
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 发送正常消息
    console.log('\n--- 发送正常消息 ---');
    await context.send(pid, '你好，Actor！');
    
    // 等待一会儿以便看到消息处理
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 发送导致崩溃的消息（应该会导致重启）
    console.log('\n--- 发送导致崩溃的消息 ---');
    await context.send(pid, 'crash');
    
    // 等待一会儿以便看到重启事件
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 再次发送正常消息，验证重启是否成功
    console.log('\n--- 重启后发送正常消息 ---');
    await context.send(pid, '你好，已重启的Actor！');
    
    // 等待一会儿以便看到消息处理
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 停止 Actor
    console.log('\n--- 停止 Actor ---');
    await context.send(pid, 'stop');
    
    // 等待一会儿以便看到停止事件
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 尝试发送消息给已停止的 Actor（应该产生 DeadLetter 事件）
    console.log('\n--- 尝试发送消息给已停止的 Actor ---');
    await context.send(pid, '这条消息应该变成无效信件');
    
    // 等待一会儿以便看到无效信件事件
    await new Promise(resolve => setTimeout(resolve, 500));

    console.log('\n示例运行完成!');

  } catch (error) {
    console.error('示例运行出错:', error);
  } finally {
    // 确保系统资源被释放
    await system.terminate();
  }
}

// 运行示例
runExample().catch(console.error); 